package com.effectiv.gooruda.rest.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import org.springframework.stereotype.Component;

import com.effectiv.gooruda.rest.domain.Permission;
import com.effectiv.gooruda.rest.domain.Role;
import com.effectiv.gooruda.rest.exception.DuplicateDataException;
import com.effectiv.gooruda.rest.exception.NoDataFoundException;
import com.effectiv.gooruda.rest.ext.ExtResponse;
import com.effectiv.gooruda.rest.service.api.PermissionService;
import com.effectiv.gooruda.rest.service.api.RoleService;

@Slf4j
@Component
public class RoleServiceImpl extends RoleService {

	
	@Autowired
	private PermissionService permissionService;

	
	public Response save(Role role) {
		// Note - a patch that works now, need to figure out changes
		Role r = findByName(role.getName());

		if (r != null) {
			throw new DuplicateDataException("Role with name " + role.getName()
					+ " already exists.");
		}

		
		getTemplate().save(role, getCollection());

		ExtResponse res = new ExtResponse();
		res.setId(role.getId());
		res.setMessage("Role added successfully.");
		
		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res, ExtResponse.class);
		
		ResponseBuilder builder = Response.ok(entity);
		
		return builder.build();
	}

	
	public Role findByName(String role) {
		
		Query query = new Query();
		query.addCriteria(Criteria.where("name").is(role));

		Role r = getTemplate().findOne(query, Role.class, getCollection());
		return r;
	}

	
	public Role addPermission(String roleName, String permissionName) {
		Role r = findByName(roleName);

		if (r == null) {
			throw new NoDataFoundException("No role found for role name - "
					+ roleName);
		}

		Permission p = permissionService.findByName(permissionName);

		if (p == null) {
			throw new NoDataFoundException(
					"No permission found for permission name - "
							+ permissionName);
		}

		List<Permission> permissions = r.getPermissions();

		log.debug("Permissions existing = {}", permissions);

		if (permissions == null) {
			permissions = new ArrayList<Permission>();
		}

		if (permissions.contains(p)) {
			log.debug("Permission already attached to role = {}", p);
			throw new DuplicateDataException("Permission - " + permissionName
					+ " already associated with role - " + roleName);
		}

		permissions.add(p);
		r.setPermissions(permissions);

		getTemplate().save(r, getCollection());

		return r;
	}

	
	public Role addPermissions(String roleName, List<String> permissions) {
		
		log.debug("Permissions = {}", permissions);

		Role role = findByName(roleName);

		if (role == null) {
			throw new NoDataFoundException("No role found for role name - "
					+ roleName);
		}

		List<Permission> existingPermissions = role.getPermissions();

		if (existingPermissions == null) {
			existingPermissions = new ArrayList<Permission>();
		}

		for (String p : permissions) {
			Permission permission = permissionService.findByName(p);
			
			log.debug("Retrieved permission = {}", permission);
			
			if (p == null) {
				throw new NoDataFoundException(
						"No permission found for permission name - " + p);
			}

			if (existingPermissions.contains(permission)) {
				log.debug("Permission already attached to role = {}", p);
				throw new DuplicateDataException("Permission - " + p
						+ " already associated with role - " + roleName);
			}
			existingPermissions.add(permission);
		}
		
		
		log.debug("Permissions before saving = {}", existingPermissions);
		
		role.setPermissions(existingPermissions);

		getTemplate().save(role, getCollection());

		return role;
	}

	
	public Role findOne(String id) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(id));

		Role r = getTemplate().findOne(query, Role.class, getCollection());
		return r;
	}

}
